/**
 * 函数模块 (zh-function.js) 使用示例
 * 演示中文函数封装类的各种功能
 */

// 导入函数模块（同时支持 CommonJS 和 ES 模块）
const 函数 = require('../../zh/公共函数/zh-function.js').函数 || require('../../zh/公共函数/zh-function.js').default;

console.log('===== 函数模块使用示例 =====\n');

// ========== 基本函数操作 ==========
console.log('1. 基本函数操作:');

// 创建函数实例
const 加法函数 = new 函数((a, b) => a + b);
const 问候函数 = new 函数(name => `你好，${name}！`);

// 获取原始函数
const 原始函数 = 加法函数.取值();
console.log(`原始函数类型: ${typeof 原始函数}`);

// 调用函数
const 结果1 = 加法函数.调用(null, 5, 3);
const 结果2 = 问候函数.调用(null, '张三');
console.log(`加法结果: ${结果1}`);
console.log(`问候结果: ${结果2}`);

// 使用 bind 绑定上下文
const 计算器 = {
  基数: 10,
  相加: function(a, b) {
    return this.基数 + a + b;
  }
};

const 绑定函数 = new 函数(计算器.相加);
const 上下文绑定 = 绑定函数.绑定(计算器, 5);
const 绑定结果 = 上下文绑定.调用(null, 3);
console.log(`绑定上下文结果: ${绑定结果}`);
console.log();

// ========== 延迟执行 ==========
console.log('2. 延迟执行:');

// 创建延迟执行的函数
const 延迟任务 = new 函数(() => {
  console.log('延迟执行的函数被调用了！');
  return '延迟任务完成';
});

// 延迟1秒执行
console.log('设置延迟执行，将在1秒后执行...');
const 延迟控制 = 延迟任务.延迟执行(1000);

// 延迟函数可以取消
// 延迟控制.清除(); // 取消延迟执行

// 带参数的延迟执行
const 参数延迟 = new 函数((name, age) => {
  console.log(`延迟执行：姓名=${name}，年龄=${age}`);
  return `${name}的信息已处理`;
});

console.log('设置带参数的延迟执行，将在1.5秒后执行...');
参数延迟.延迟执行(1500, '李四', 28);
console.log();

// ========== 节流函数 ==========
console.log('3. 节流函数:');

// 创建一个模拟频繁调用的函数
let 节流计数 = 0;
const 高频函数 = new 函数(() => {
  节流计数++;
  console.log(`高频函数被调用，计数: ${节流计数}`);
  return 节流计数;
});

// 创建节流函数（间隔2000毫秒）
const 节流处理 = 高频函数.节流(2000, true); // 立即执行首次调用

console.log('模拟高频调用（将在2秒内只执行一次）:');
节流处理.调用();
节流处理.调用();
节流处理.调用();

// 模拟稍后再次调用
console.log('设置2.5秒后再次调用...');
setTimeout(() => {
  console.log('2.5秒后再次调用:');
  节流处理.调用();
}, 2500);

// 非立即执行的节流
const 非立即节流 = 高频函数.节流(1500, false);
console.log('非立即执行的节流函数已创建');
console.log();

// ========== 防抖函数 ==========
console.log('4. 防抖函数:');

let 防抖计数 = 0;
const 搜索函数 = new 函数(keyword => {
  防抖计数++;
  console.log(`搜索关键词: "${keyword}"，搜索次数: ${防抖计数}`);
  return `搜索结果: ${keyword}`;
});

// 创建防抖函数（等待500毫秒）
const 防抖搜索 = 搜索函数.防抖(500, true); // 立即执行首次调用

console.log('模拟连续输入搜索关键词:');
防抖搜索.调用(null, '中');
setTimeout(() => 防抖搜索.调用(null, '中文'), 100);
setTimeout(() => 防抖搜索.调用(null, '中文函'), 200);
setTimeout(() => 防抖搜索.调用(null, '中文函数'), 300);

// 延迟执行的防抖
const 延迟防抖 = 搜索函数.防抖(300, false);
console.log('延迟执行的防抖函数已创建');
console.log();

// ========== 函数包装 ==========
console.log('5. 函数包装:');

// 前置包装
const 记录函数 = new 函数(n => {
  console.log(`执行计算: ${n} × 2`);
  return n * 2;
});

// 添加前置日志
const 带日志的函数 = 记录函数.前置包装((...args) => {
  console.log(`[前置] 准备处理参数: ${args.join(', ')}`);
});

console.log('使用前置包装函数:');
const 前置结果 = 带日志的函数.调用(null, 10);
console.log(`前置包装结果: ${前置结果}`);

// 后置包装
const 带统计的函数 = 记录函数.后置包装((...args) => {
  console.log(`[后置] 参数处理完成: ${args.join(', ')}`);
});

console.log('\n使用后置包装函数:');
const 后置结果 = 带统计的函数.调用(null, 20);
console.log(`后置包装结果: ${后置结果}`);

// 组合包装（同时使用前置和后置）
const 完整包装 = 记录函数
  .前置包装(() => console.log('计算开始'))
  .后置包装(() => console.log('计算结束'));

console.log('\n使用完整包装函数:');
完整包装.调用(null, 30);
console.log();

// ========== 函数重试 ==========
console.log('6. 函数重试:');

let 重试次数 = 0;
const 可能失败的函数 = new 函数(async () => {
  重试次数++;
  console.log(`尝试执行第 ${重试次数} 次`);
  if (重试次数 < 3) {
    throw new Error('操作暂时失败');
  }
  return '操作成功！';
});

// 创建重试函数（最多5次，间隔500毫秒）
const 重试操作 = 可能失败的函数.重试(5, 500);

console.log('开始带重试的操作:');
// 注意：实际使用时应使用 await
setTimeout(async () => {
  try {
    const 重试结果 = await 重试操作.调用();
    console.log(`重试最终结果: ${重试结果}`);
  } catch (error) {
    console.error(`所有重试都失败了: ${error.message}`);
  }
}, 100);
console.log();

// ========== 函数缓存 ==========
console.log('7. 函数缓存:');

// 创建一个模拟耗时计算的函数
const 耗时计算 = new 函数(n => {
  console.log(`计算 ${n} 的斐波那契数...`);
  // 简单的斐波那契计算
  if (n <= 1) return n;
  let a = 0, b = 1;
  for (let i = 2; i <= n; i++) {
    const temp = a + b;
    a = b;
    b = temp;
  }
  return b;
});

// 创建缓存函数
const 缓存计算 = 耗时计算.缓存();

console.log('首次计算斐波那契数:');
console.log(`结果: ${缓存计算.调用(null, 30)}`);

console.log('\n使用缓存计算相同的值:');
console.log(`结果: ${缓存计算.调用(null, 30)}`); // 不会显示计算日志

console.log('\n计算新的值:');
console.log(`结果: ${缓存计算.调用(null, 25)}`); // 首次计算

console.log('\n再次使用缓存:');
console.log(`结果: ${缓存计算.调用(null, 25)}`); // 使用缓存
console.log();

// ========== 超时控制 ==========
console.log('8. 超时控制:');

const 长时间操作 = new 函数(() => {
  console.log('开始执行长时间操作...');
  // 模拟长时间计算
  const start = Date.now();
  while (Date.now() - start < 2000) {} // 阻塞2秒
  console.log('长时间操作完成');
  return '操作完成';
});

// 创建带超时控制的函数（1秒超时）
const 超时控制操作 = 长时间操作.超时控制(1000, new Error('操作超时！'));

console.log('开始执行带超时控制的操作:');
// 实际使用时应使用 await
setTimeout(async () => {
  try {
    const 结果 = await 超时控制操作.调用();
    console.log(`操作结果: ${结果}`);
  } catch (error) {
    console.error(`操作出错: ${error.message}`);
  }
}, 100);
console.log();

// ========== 静态方法 ==========
console.log('9. 静态方法:');

// 是否函数
console.log(`检查函数类型:`);
console.log(`- 函数: ${函数.是否函数(() => {})}`);
console.log(`- 字符串: ${函数.是否函数('hello')}`);
console.log(`- 对象: ${函数.是否函数({})}`);

// 创建空函数
const 空函数 = 函数.空();
console.log(`\n空函数调用结果: ${空函数.调用()}`);

// 创建恒等函数
const 恒等函数 = 函数.恒等();
console.log(`\n恒等函数测试:`);
console.log(`- 数字: ${恒等函数.调用(null, 42)}`);
console.log(`- 字符串: ${恒等函数.调用(null, 'test')}`);
console.log(`- 对象:`, 恒等函数.调用(null, { a: 1 }));

// 函数组合（从右到左）
const 转大写 = str => str.toUpperCase();
const 添加感叹号 = str => str + '!';
const 添加前缀 = str => 'Hello, ' + str;

const 组合函数 = 函数.组合(转大写, 添加感叹号, 添加前缀);
console.log(`\n函数组合 (Hello, world -> HELLO, WORLD!):`);
console.log(`结果: ${组合函数.调用(null, 'world')}`);

// 函数管道（从左到右）
const 管道函数 = 函数.管道(添加前缀, 添加感叹号, 转大写);
console.log(`\n函数管道 (world -> Hello, world! -> HELLO, WORLD!):`);
console.log(`结果: ${管道函数.调用(null, 'world')}`);

// 多函数管道
const 数字处理 = 函数.管道(
  x => x * 2,
  x => x + 10,
  x => `结果: ${x}`
);
console.log(`\n数字处理管道 (5 -> 10 -> 20 -> "结果: 20"):`);
console.log(`结果: ${数字处理.调用(null, 5)}`);
console.log();

// ========== 实际应用场景 ==========
console.log('10. 实际应用场景:');

// 场景1: 表单验证
console.log('场景1: 表单验证');

const 验证邮箱 = 函数.管道(
  str => ({ value: str, isValid: true, error: '' }),
  data => {
    if (!data.value) {
      data.isValid = false;
      data.error = '邮箱不能为空';
    }
    return data;
  },
  data => {
    if (data.isValid) {
      const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
      if (!emailRegex.test(data.value)) {
        data.isValid = false;
        data.error = '请输入有效的邮箱地址';
      }
    }
    return data;
  }
);

console.log('验证邮箱: ""');
console.log(验证邮箱.调用(null, ''));

console.log('\n验证邮箱: "invalid-email"');
console.log(验证邮箱.调用(null, 'invalid-email'));

console.log('\n验证邮箱: "user@example.com"');
console.log(验证邮箱.调用(null, 'user@example.com'));

// 场景2: 事件处理优化
console.log('\n场景2: 事件处理优化');

// 创建滚动事件处理函数
const 滚动处理 = new 函数(() => {
  const scrollY = window.scrollY || document.documentElement.scrollTop;
  console.log(`页面滚动位置: ${scrollY}px`);
  // 这里可以添加实际的滚动处理逻辑
});

// 应用节流优化
const 节流滚动 = 滚动处理.节流(100);

console.log('创建了节流优化的滚动处理函数');
console.log('每100毫秒内只会处理一次滚动事件');

// 场景3: API调用重试和缓存
console.log('\n场景3: API调用重试和缓存');

// 模拟API调用
const 模拟API调用 = new 函数(async id => {
  console.log(`调用API获取数据 ID=${id}`);
  // 模拟网络延迟
  await new Promise(resolve => setTimeout(resolve, 300));
  // 模拟偶发性失败
  if (Math.random() < 0.3) {
    throw new Error('网络错误，请重试');
  }
  return { id, name: `项目 ${id}`, timestamp: new Date().toISOString() };
});

// 应用重试和缓存
const 增强API调用 = 模拟API调用
  .重试(3, 500) // 最多重试3次，间隔500ms
  .缓存();      // 缓存结果

console.log('创建了带重试和缓存的API调用函数');
console.log('首次调用会尝试3次，后续调用使用缓存');

// 场景4: 性能监控
console.log('\n场景4: 性能监控');



// 创建监控的计算函数
const 性能监控包装 = new 函数((fn, label = '未命名操作') => {
  return function(...args) {
    const start = performance.now();
    const result = fn.apply(this, args);
    const end = performance.now();
    console.log(`${label} 执行时间: ${(end - start).toFixed(2)}ms`);
    return result;
  };
});

const 监控计算 = new 函数(性能监控包装.调用(null, n => {
  let sum = 0;
  for (let i = 0; i < n * 1000000; i++) {
    sum += i % 10;
  }
  return sum;
}, '大型计算'));

console.log('创建了性能监控的计算函数');
console.log('执行时会显示详细的性能信息');

console.log('\n===== 函数模块使用示例结束 =====');

// 注意：由于某些示例使用异步操作，实际运行时可能需要等待一段时间才能看到所有输出